์ด๋ฒ์๋ leaflet๊ณผ crosstalk์ ํ์ฉํ์ฌ ์ง๋ ์๊ฐํ ๋ฐ ์์ ฏ ๊ฐ ์ํธ์์ฉ์ ๋ค๋ค๋ณผ ๊ฒ์
๋๋ค. leaflet์ ์ง๋ ์๊ฐํ๋ฅผ ์ํ ์๋ฐ์คํฌ๋ฆฝํธ์ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ Leaflet.js์ R ์ธํฐํ์ด์ค์
๋๋ค. crosstalk์ ํ๋์ ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ์ค์ฌ์ผ๋ก ์ฌ๋ฌ ์์ ฏ๋ค์ ์ฐ๊ฒฐํ๋ฉฐ, linked brushing, filtering ๋ฑ์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฒ ์ค์ต์์ ์ฌ์ฉํ๋ crosstalk, leaflet, d3scatter ํจํค์ง๋ ์๋ ๊นํ๋ธ์์ ๋ฐ์์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
devtools::install_github("dmurdoch/leaflet@crosstalk4")
devtools::install_github("rstudio/leaflet")
devtools::install_github("jcheng5/d3scatter")
์ง๋๋ฅผ ์์ฑํ๋ ์ฝ๋๋ ๋งค์ฐ ๊ฐ๋จํ๋ฉฐ ์ง๊ด์ ์
๋๋ค. leaflet() %>% addTiles()๋ก ์ง๋๋ฅผ ๊ทธ๋ฆฌ๊ณ mymap์ด๋ผ๋ ๋ณ์์ ์ ์ฅํ์์ต๋๋ค. ์ผ์ชฝ ์ง๋๋ ์ด ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋๋ก ์ถ๋ ฅํ ๊ฒ์ด๊ณ , ์ค๋ฅธ์ชฝ ์ง๋๋ setView() ํจ์๋ก ์ขํ์ ํ๋๋ฅผ ์ง์ ํ์ฌ ์ถ๋ ฅํ ๊ฒ์
๋๋ค. crosstalk::bscols() ํจ์๋ ๋จ์ํ ์ง๋๋ฅผ ๋๋ํ ๋ฐฐ์ดํ๊ธฐ ์ํด์ ์ฌ์ฉํ์์ผ๋ฉฐ, ์ง๋์๋ ์๋ฌด๋ฐ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค.
library(tidyverse)
library(leaflet)
mymap = leaflet() %>% addTiles()
crosstalk::bscols(
mymap,
mymap %>% setView(126.982, 37.5502, zoom=10)
)
leaflet์ ํตํด์ ์์ฝ๊ฒ ์ง๋๋ฅผ ๊ทธ๋ฆด ์ ์์ ๋ฟ ์๋๋ผ, ์ง๋ ์์ ๋ฐ์ดํฐ๋ฅผ ํํํ๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค. ๋ค์์ ์ง๋ ์์ ์ ์ ํํํ๋ ์์ ๋ค์
๋๋ค. ์๊ฒฝ๋๋ก ํํ๋ ์ขํ๊ฐ ์๋ค๋ฉด ์์ฝ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ง๋ ์์ ํํํ ์ ์์ต๋๋ค.
points1 = mymap %>%
addMarkers(lng=c(126.882, 126.982, 127.082),
lat=c(37.4502, 37.5502, 37.6502),
label=c('์์1','์์2','์์3'))
points2 = mymap %>%
addMarkers(data = quakes[1:20,], lng=~long, lat=~lat, label=~as.character(mag))
crosstalk::bscols(points1,points2)
์ง๋ฆฌ ๋ฐ์ดํฐ๋ .shp, .json, .csv ๋ฑ ๋ค์ํ ํํ๋ก ์กด์ฌํฉ๋๋ค. ์ด๋ฒ์๋ .json ํ์์ ํ์ผ์ ๊ฐ์ง๊ณ ์ค์ต์ ์งํํด๋ณด๊ฒ ์ต๋๋ค. ์ค์ต์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ 2016๋
๊ตญํ์์ ์ด์ ์ ์์ธ ์ง์ญ ๊ฐํ๊ฒฐ๊ณผ ๋ฐ์ดํฐ์
๋๋ค. ์ ์ฒ๋ฆฌ geojsonioํจํค์ง๋ฅผ ํตํด์ SpatialPolygonsDataFrame ํด๋์ค๋ก ํ์ผ์ ์ฝ์ด์ต๋๋ค. SpatialPolygonsDataFrame์ ์ขํ๊ณ, ํด๋ฆฌ๊ณค ์ขํ ๋ฑ์ ์ง๋ฆฌ์ ๋ณด์ ์ผ๋ฐ์ ์ธ ๋ฐ์ดํฐํ๋ ์์ ๊ฒฐํฉํด๋์ ํด๋์ค์
๋๋ค. election@polygons๋ฅผ ํตํด์ ํด๋ฆฌ๊ณค ๋ฆฌ์คํธ์ ์ ๊ทผํ ์ ์๊ณ , election@data๋ฅผ ํตํด์ ๋ฐ์ดํฐํ๋ ์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
election = geojsonio::geojson_read("data/election.json", what = "sp")
cat("class(election) : ", class(election))
## class(election) : SpatialPolygonsDataFrame
cat("class(election@polygons) : ", class(election@polygons))
## class(election@polygons) : list
cat("class(election@data) : ", class(election@data))
## class(election@data) : data.frame
# ๋ฐ์ดํฐํ๋ ์์ ๊ฐ๋จํ ์ ์ฒ๋ฆฌ๋ฅผ ํด์ค ์์
colnames(election@data) = colnames(election@data) %>% str_replace(" ","")
์ง๋์ ํด๋ฆฌ๊ณค์ ํํํ๋ ๊ฒ์ ์ ์ ์ฐ๋ ์ผ๋งํผ์ด๋ ๊ฐ๋จํฉ๋๋ค. ์ผ์ชฝ ์์ ์์ ๋ณผ ์ ์๋ฏ์ด addPolygons()์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด์ฃผ๋ ๊ฒ๋ง๋ก ํด๋ฆฌ๊ณค์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์ํ๋ ๋ณ์๋ฅผ ์ ๋ฌํ๋ฉด ๊ฐ๋จํ ๋ผ๋ฒจ์ ํํํ๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค. ์ค๋ฅธ์ชฝ ์์ ์์๋ ๊ฒฝ๊ณ์ ๊ณผ ํด๋ฆฌ๊ณค ๋ด๋ถ ์, ํ์ด๋ผ์ดํธ๋ฅผ ์ถ๊ฐํ๊ณ , ๋ผ๋ฒจ์ ์์ ํ๊ณ , ์ ๊ฑฐ๊ตฌ๋ณ ํด๋ฆฌ๋ผ์ธ๊ณผ ๋ฒ๋ก๋ฅผ ์ถ๊ฐ์ ์ผ๋ก ๊ฒน์ณ์ฃผ์์ต๋๋ค. add~ ํจ์๋ค์ด ํ๋์ ๋ ์ด์ด๋ฅผ ๊ณต์ ํ๋ค๋ฉด, leaflet()์์ ๋จผ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๊ฒ๋ ์ข์ต๋๋ค.
poly1 = mymap %>% addPolygons(data=election,label=~๋น์ )
# ์ง๋์ ์์ ์
ํ๊ธฐ ์ํด์ ํ๋ ํธ ์์ฑ
pal = colorFactor(c("#0D7440", "#2A88C5", "#C10D0D"), c("๊ตญ๋ฏผ์๋น", "๋๋ถ์ด๋ฏผ์ฃผ๋น","์๋๋ฆฌ๋น"))
# ํดํ์ ๋ด์ ์ ๋ณด ์์ฑ
labs = lapply(seq(nrow(election@data)), function(i) {
paste0( '<p><b>', election@data[i, "์ ๊ฑฐ๊ตฌ"]," : ",election@data[i, "์๋ฉด๋๋ช
"], '</b></p><p>',
"<b>๋น์ : ", election@data[i, "๋น์ "], '</b><p></p>',
"๊ตญ๋ฏผ์๋น : ", election@data[i, "๊ตญ๋ฏผ์๋น"],'</p><p>',
"๋๋ถ์ด๋ฏผ์ฃผ๋น : ", election@data[i, "๋๋ถ์ด๋ฏผ์ฃผ๋น"], '</p><p>',
"์๋๋ฆฌ๋น : ", election@data[i, "์๋๋ฆฌ๋น"], '</p>')
})
# ์ ๊ฑฐ๊ตฌ ๊ฒฝ๊ณ ์์ฑ
election_gu = maptools::unionSpatialPolygons(election, election$์ ๊ฑฐ๊ตฌ)
poly2 = leaflet(election) %>%
addTiles %>%
addPolygons(
# ํด๋ฆฌ๊ณค ๋ด๋ถ
fillColor = ~pal(๋น์ ), fillOpacity = 0.5,
# ํด๋ฆฌ๊ณค ๊ฒฝ๊ณ
weight = 1, opacity = 1, color = "white", dashArray=3,
# ๋ผ๋ฒจ
label=lapply(labs, htmltools::HTML),
# ํ์ด๋ผ์ดํธ
highlightOptions = highlightOptions(
color = "#00ff00", opacity = 1, weight = 2, fillOpacity = 1,
bringToFront = T, sendToBack = T))%>%
addLegend(pal = pal, values = ~๋น์ , opacity = 0.7, title = NULL, position = "bottomright") %>%
addPolylines(
data=election_gu,
weight = 1.5,
opacity = 1,
color = "black")
crosstalk::bscols(poly1, poly2)
crosstalk์ ํ๋์ ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ์ฌ๋ฌ ์์ ฏ์ ์ฐ๋์ํต๋๋ค. ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ , ์ด ๋ฐ์ดํฐ๋ก ํ๋กฏ์ ๊ทธ๋ ค์ฃผ๊ธฐ๋ง ํ๋ฉด ๋์
๋๋ค. crosstalk์ ๋ฐ์ดํฐํ๋ ์์ ์
๋ ฅ์ผ๋ก ๋ฐ๋ HTML ์์ ฏ๋ค์์ ์๋ํ๋ฉฐ, ์ฃผ์ํ ํ๊ณ์ ๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ ์์๊ฐ ์ง์ HTML ์์ ฏ์ ์ ์ ํ ์์ ํด์ผ ํ๋ค. crosstalk์ ์ค์ค๋ก ์์ ฏ๋ค์ ์ฐ๋์์ผ์ฃผ์ง๋ ์๋๋ค.
Crosstalk์ ๊ฐ๋ณ ๋ฐ์ดํฐ ํฌ์ธํธ์ ๋ํด์๋ง ์๋ํ๋ฉฐ, ๋ฐ์ดํฐ์ ๊ฒฐํฉ์ด๋ ์์ฝ์ ํํํ๋ ์์ ฏ๋ค์๋ ์๋ํ์ง ์๋๋ค. ์๋ฅผ ๋ค์ด์ ๊ฐ๋ณ ๋ฐ์ดํฐ ํฌ์ธํธ๋ฅผ ํํํ๋ ์ฐ์ ๋์๋ ์ ์ฉ๋ ์ ์์ง๋ง, ํ์คํ ๊ทธ๋จ์๋ ์ ์ฉ๋ ์ ์๋ค.
crosstalk์ ํฐ ๋ฐ์ดํฐ์ ์ ํฉํ์ง ์๋ค. ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋ก๋๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
Linked brushing์ ํ๋์ ํ๋กฏ์์ ๋ฐ์ํ ๋ธ๋ฌ์ฑ์ ์ฐ๊ฒฐ๋ ๋ค๋ฅธ ํ๋กฏ๋ค์๋ ์ ์ฉํ๋ ๊ธฐ๋ฅ์
๋๋ค. ๋จผ์ crosstalk::SharedData๋ก ๋ฐ์ดํฐํ๋ ์์ ๊ฐ์ธ ์ฌ๋ฌ ์์ ฏ๋ค์ ์ฐ๊ฒฐํ ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํด์ค๋๋ค. ์ด ๊ฐ์ฒด๋ฅผ ์ด์ฉํด์ ๋ ๊ฐ์ ๊ทธ๋ํ๋ฅผ ๊ทธ๋ ธ์ต๋๋ค. ์ดํ subplot ํจ์๋ก ๋ ๊ฐ์ ๊ทธ๋ํ๋ฅผ ๋ฌถ์ด์ฃผ๊ณ , highlight์ "plotly_selected"๋ฅผ ์ ๋ฌํด์ฃผ๋ฉด ๋ฉ๋๋ค. ํ ์ชฝ ํ๋กฏ์์ ์ ๋ค์ ์ ํํ๋ฉด ๋ค๋ฅธ ์ชฝ ํ๋กฏ์์๋ ํ์ด๋ผ์ดํธ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. crosstalk์ SharedData๊ฐ ์๋ ์ผ๋ฐ ๋ฐ์ดํฐํ๋ ์์ผ๋ก ํ๋กฏ์ ๊ทธ๋ฆฐ๋ค๋ฉด ๋น์ฐํ ์ด ๊ธฐ๋ฅ์ ์๋ํ์ง ์์ต๋๋ค.
library(crosstalk)
library(plotly)
# election@data๋ฅผ SharedData๋ก ๊ฐ์ธ ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ์์ฑ
shared_elec = SharedData$new(election@data)
p1 = plot_ly(shared_elec, x = ~์๋, y = ~๋
ธ๋ นํ์ง์, legendgroup=~๋น์ ) %>%
add_markers(color=~๋น์ , colors=c("#0D7440", "#2A88C5", "#C10D0D"), opacity=0.6)
p2 = plot_ly(shared_elec, x = ~์ฅ์ ๋ฑ๊ธ๋ณ.์ฅ์ ์ธํํฉ, y = ~๋ณด์ก์์ค, legendgroup=~๋น์ ) %>%
add_markers(color=~๋น์ , colors=c("#0D7440", "#2A88C5", "#C10D0D"), opacity=0.6)
subplot(p1,p2) %>%
layout(xaxis = list(title = "์๋"),
yaxis = list(title = "๋
ธ๋ นํ์ง์"),
xaxis2 = list(title = "์ฅ์ ์ธํํฉ"),
yaxis2 = list(title = "๋ณด์ก์์ค"),
height=400, width=850) %>%
highlight("plotly_selected")
crosstalk์ ์๋ก ๋ค๋ฅธ ์ข
๋ฅ์ ์์ ฏ๋ค ๊ฐ์๋ ์ ์๋ํฉ๋๋ค. ๋ค๋ง, ์ฌ๋ฌ ์์ ฏ๋ค์ด ์๋ก ๋ค๋ฅธ ํด๋์ค๋ฅผ ํ์๋ก ํ ๊ฒฝ์ฐ์๋ ์ฝ๊ฐ์ ์กฐ์์ด ๋ ํ์ํฉ๋๋ค. ๋ค์์ ์ง๋์ ์ฐ์ ๋, ํ
์ด๋ธ์ ์ฐ๊ฒฐํ ์์ ์
๋๋ค. election์ ํด๋์ค๋ SpatialPolygonsDataFame์
๋๋ค. plot_ly ํจ์๋ SpatialPolygonsDataFrame ํด๋์ค์ ๋ํด์ ์๋ํ์ง ์์ผ๋ฏ๋ก, election@data๋ฅผ ๋ณ๋๋ก ๊ณต์ ๋ฐ์ดํฐ๋ก ๋ง๋ค์ด์ฃผ๋ฉด์ group=shared_elec$groupName() ์ธ์๋ฅผ ์ ๋ฌํ์ต๋๋ค. ์ฆ shared_elec๊ณผ shared_elec_df๊ฐ ํ ๊ทธ๋ฃน์ผ๋ก ์ฐ๊ฒฐ๋ ์ํ์ด๊ณ , ์ฐ๋์ด ์ ์ด๋ฃจ์ด์ง๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. shared_elec_dt ์ญ์ ๊ทธ๋ฃน์ ์ง์ ํ์ฌ ์ฐ๋์์ผฐ์ต๋๋ค.
library(d3scatter)
shared_elec = SharedData$new(election)
shared_elec_df = SharedData$new(election@data, group=shared_elec$groupName())
shared_elec_dt = crosstalk::SharedData$new(election@data %>%
select(์ ๊ฑฐ๊ตฌ,๋น์ ,์๋ฉด๋๋ช
,์๋,๋
ธ๋ นํ์ง์), group=shared_elec$groupName())
DT::datatable(shared_elec_dt, width="100%")
bscols(
d3scatter(data=shared_elec_df, x=~์๋,y=~๋
ธ๋ นํ์ง์,color=~๋น์ , height=300, width="100%"),
d3scatter(data=shared_elec_df, x=~์ฅ์ ๋ฑ๊ธ๋ณ.์ฅ์ ์ธํํฉ,y=~์ฌ์
์ฒด์,color=~๋น์ , height=300, width="100%")
)
leaflet(shared_elec) %>%
addProviderTiles("CartoDB.Positron") %>%
setView(126.982, 37.5502, zoom=10) %>%
addPolygons(
fillColor = ~pal(๋น์ ),
weight = 1,
opacity = 1,
color = "white",
dashArray=3,
fillOpacity = 0.5,
label = lapply(labs, htmltools::HTML)) %>%
addLegend(pal = pal, values = ~๋น์ , opacity = 0.7, title = NULL, position = "bottomright") %>%
addPolylines(
data=election_gu,
weight = 1.5,
opacity = 1,
color = "black")
ํํฐ๋ง์ ๋ง ๊ทธ๋๋ก ํน์ ๋ฐ์ดํฐ ํฌ์ธํธ๋ฅผ ํํฐ๋งํ๋ ๊ธฐ๋ฅ์ ๋๋ค. ์์ ์ ํจ๊ป ๋ณด๊ฒ ์ต๋๋ค.
bscols(
list(filter_checkbox("๋น์ ", "๋น์ ", shared_elec_df, ~๋น์ , inline=T),
filter_slider("์๋", "์๋", shared_elec_df, ~์๋, width="100%"),
filter_select("๋", "๋", shared_elec_df, ~์๋ฉด๋๋ช
)),
d3scatter(shared_elec_df, ~์๋, ~๊ธฐ์ด์๊ธ์์ธ์์, ~๋น์ , width="100%", height=250),
d3scatter(shared_elec_df, ~์๋, ~๊ธฐ์ด์๊ธ์์ธ์์, ~๋น์ , width="100%", height=250)
)
DT::datatable(shared_elec_dt, width="100%")